{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 实例4：合并不同PDF文档以便一次批量打印或存档"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "公司船务部一个重要任务就是需要准备每单货物的发票，从系统导出发票时是默认存为一个PDF文档，在打印的时候，有多少个文件，就需要点多少次“打印”。如果能够将当天的发票PDF档合并在一个PDF里面，只需要点一次“打印”即可完成。在网上我们可以搜到很多PDF合并软件，但在真实工作环境下并不是非常实用，比如有些PDF有封面页，我们在合并的时候只需要第一个文件的封面即可，后续的只要封面后的内容。而PDF合并软件是简单粗暴的直接将所有内容合并，那合并后的文件就会多出很多我们不需要的“封面”。Python有一个库`PyPDF2`可轻松解决这个小问题，可以实现任意选定页面的合并。通过文件夹遍历，可以将不同文件夹下的PDF按选定的页面合并在一起，方便实用，毫不含糊。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Wall time: 130 ms\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "import PyPDF2 #可从PDF文档提取信息\n",
    "import os #用于获取需要合并的PDF文件所在路径\n",
    "path=\"data/\" # 文件夹路径\n",
    "#1.获取需要用于合并的文件名及路径\n",
    "files=[]\n",
    "for file in os.listdir(path):\n",
    "    if file.endswith(\".pdf\"): #排除文件夹内的其它干扰文件，只获取PDF文件\n",
    "        files.append(path+file) \n",
    "#2.获取每个PDF文件里面需要的信息并添加到写入文件\n",
    "pdf_writer=PyPDF2.PdfFileWriter()\n",
    "for file in files:\n",
    "    pdf_obj=open(file,'rb')# 以二进制读取，将保留PDF中的所有信息\n",
    "    pdf_reader=PyPDF2.PdfFileReader(pdf_obj)\n",
    "    for page_num in range(1,pdf_reader.numPages): #不要第一页的封面，从第2页开始获取\n",
    "        page_obj=pdf_reader.getPage(page_num)\n",
    "        pdf_writer.addPage(page_obj)\n",
    "#3.写入并保存汇总PDF文件\n",
    "pdf_output_file=open(\"data\\combined_inv.pdf\",'wb') #以二进制写入，将保留源PDF中的所有信息\n",
    "pdf_writer.write(pdf_output_file)\n",
    "pdf_output_file.close()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "我们先导入`PyPDF2`和`os`库。若未安装`PyPDF2`,可运行\"cmd.exe\"，输入\"pip install PyPDF2\"，请注意PyPDF2有大小写要求，不然无法安装。\n",
    "\n",
    "然后定义pyth为我们需要操作的文件夹的路径。随后就需要获取我们待合并的所有PDF文件的文件名和路径，并存入我们定义的列表`files`。如果文件夹内有非pdf文件，也会被获取。比如如下，我们可以看到这个路径下有一个txt文件,那可不是我们想要的。因此需要加入一个筛选，`file.endswith(\".pdf\")`我们只要以\".pdf\"结尾的文件。这样得到的files列表就是我们需要合并的文件及其路径了。`files.append(path+file)`里面\"path+file\"是用于将路径和文件名连接起来，这样才能得到文件的完整路径，程序才可以找得到这个文件。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['combined_inv.pdf',\n",
       " 'INV1.pdf',\n",
       " 'INV2.pdf',\n",
       " 'INV3.pdf',\n",
       " 'INV4.pdf',\n",
       " 'INV5.pdf',\n",
       " 'test.txt']"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "os.listdir(path)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['data/INV1.pdf',\n",
       " 'data/INV2.pdf',\n",
       " 'data/INV3.pdf',\n",
       " 'data/INV4.pdf',\n",
       " 'data/INV5.pdf']"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "files"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "待合并的PDF文件路径搜集完后，就可以开始逐个读取其中想要的页面了。按照PyPDF2的操作要求，我们需要按如下步骤来进行读取和写入：\n",
    "\n",
    "**1. 打开PDF文件，得到一个“读取”对象。读取对象相当于是盛装这个PDF文件内容的容器。**\n",
    "\n",
    "**2．创建一个 “写入” 对象，相当于另一个容器，用于向其中转移上一个步骤读取出来的内容。**\n",
    "    \n",
    "**3．将页面从 “读取” 容器倒入 “写入” 容器之中。**\n",
    "    \n",
    "**4．待“写入”容器装完所有需要的内容后，写入并输出新的 PDF。**\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`pdf_writer=PyPDF2.PdfFileWriter()`就是用于装待写入文件的容器，`PyPDF2.PdfFileWriter()`是固定写法，其原理就无需深究了。然后我们读取每个PDF文件，先将打开PDF文件，并存到`pdf_obj`，然后使用`PyPDF2.PdfFileReader(pdf_obj)`读取其中的信息，存到`pdf_reader`，然后再获取其中的页面，此处我们将其中第2页及以后的页（如果有的话）面提取出来。因此`range(1,pdf_reader.numPages)`是从1开始，因为`range`是从0索引开始，因此1代表第二页。“pdf_reader.numPages”是该PDF文件的总页数。`pdf_reader.getPage(page_num)`可获得其中每页的信息，我们将它存入`page_obj`容器。随后我们使用addPage方法`pdf_writer.addPage(page_obj)`将`page_obj`中的信息放入最开始的pdf_writer容器中。\n",
    "\n",
    "就这样逐个打开相关PDF文件，读取文件，获取页面信息，然后存入pdf_writer容器。如同吃火锅时，从不同的佐料中取我们想要的佐料和量，加入到自己的油碟中一样。\n",
    "\n",
    "待所有想要合并的页面都加入pdf_writer容器之后，就可以写入新的PDF文件并保存了。先新建一个名为“combined_inv.pdf”的文件，并以二进制打开`open(\"data\\combined_inv.pdf\",'wb')`。然后将pdf_writer容器中的所有信息用write方法写入到新的文件`pdf_writer.write(pdf_output_file)`。最后关闭该文件`pdf_output_file.close()`，操作完成。合并后的PDF文件`combined_inv.pdf`如下：\n",
    "![](images\\combine_inv.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
